package com.sweetcircle.websocket;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sweetcircle.domain.dto.MessageSendDto;
import com.sweetcircle.domain.dto.TokenUserInfoDto;
import com.sweetcircle.domain.enums.MessageTypeEnum;
import com.sweetcircle.domain.po.UserInfo;
import com.sweetcircle.mapper.ChatMessageMapper;
import com.sweetcircle.mapper.UserInfoMapper;
import com.sweetcircle.service.UserInfoService;
import com.sweetcircle.utils.AnanUtils;
import com.sweetcircle.utils.RedisComponet;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component("channelContextUtils")
public class ChannelContextUtils {

    public static final ConcurrentMap<String, Channel> USER_CONTEXT_MAP = new ConcurrentHashMap<>();
    public static final ConcurrentMap<String, ChannelGroup> GROUP_CONTEXT_MAP = new ConcurrentHashMap<>();
    private static final Logger logger = LoggerFactory.getLogger(ChannelContextUtils.class);
    @Resource
    private RedisComponet redisComponet;


    private static void sendMsg(MessageSendDto messageSendDto, String receiveId) {
        if (receiveId == null) {
            return;
        }
        Channel sendChannel = USER_CONTEXT_MAP.get(receiveId);
        if (sendChannel == null) {
            return;
        }
        sendChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(messageSendDto)));
    }

    /**
     * 加入通道
     *
     * @param tokenUserInfoDto
     * @param channel
     */
    public void addContext(TokenUserInfoDto tokenUserInfoDto, Channel channel) {
        try {
            String userId = tokenUserInfoDto.getUserId();
            // 根据渠道ID生成唯一的属性键
            String channelId = channel.id().toString();
            AttributeKey<Object> attributeKey = null;

            // 检查是否存在对应的属性键，如果不存在，则创建新的属性键；否则使用已存在的属性键
            if (!AttributeKey.exists(channelId)) {
                attributeKey = AttributeKey.newInstance(channelId);
            } else {
                attributeKey = AttributeKey.valueOf(channelId);
            }

            // 将用户ID绑定到渠道的属性上
            channel.attr(attributeKey).set(userId);

            // 将用户与渠道的关联存储到映射中
            USER_CONTEXT_MAP.put(userId, channel);

            // 在Redis中记录用户的心跳
            redisComponet.saveUserHeartBeat(userId);

//            //发送消息
//            MessageSendDto messageSendDto = new MessageSendDto();
//            sendMsg(messageSendDto, userId);
        } catch (Exception e) {
            logger.error("初始化链接失败", e);
        }
    }

    /**
     * 删除通道连接异常
     *
     * @param channel
     */
    public void removeContext(Channel channel) {
        Attribute<String> attribute = channel.attr(AttributeKey.valueOf(channel.id().toString()));
        String userId = attribute.get();
        if (!AnanUtils.isEmpty(userId)) {
            USER_CONTEXT_MAP.remove(userId);
        }
        redisComponet.removeUserHeartBeat(userId);
    }

    public void closeContext(String userId) {
        if (AnanUtils.isEmpty(userId)) {
            return;
        }
        redisComponet.cleanUserTokenByUserId(userId);
        Channel channel = USER_CONTEXT_MAP.get(userId);
        USER_CONTEXT_MAP.remove(userId);
        if (channel != null) {
            channel.close();
        }
    }

    public void sendMessage(MessageSendDto messageSendDto) {
        if (messageSendDto.getMessageCode() == 1) {  // 发送消息给用户
            sendMsg(messageSendDto, messageSendDto.getContactId());
        } else if (messageSendDto.getMessageCode() == 2) {
            if (messageSendDto.getContactId() == null) {
                logger.error("发送消息给用户失败 messageSendDto.getContactId() == null");
                return;
            }
            ChannelGroup group = GROUP_CONTEXT_MAP.get(messageSendDto.getContactId());
            if (group == null) {
                return;
            }
            group.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(messageSendDto)));

            //移除群聊
            MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByType(messageSendDto.getMessageType());
            if (MessageTypeEnum.LEAVE_GROUP == messageTypeEnum || MessageTypeEnum.REMOVE_GROUP == messageTypeEnum) {
                String userId = (String) messageSendDto.getExtendData();
                redisComponet.removeUserContact(userId, messageSendDto.getContactId());
                Channel channel = USER_CONTEXT_MAP.get(userId);
                if (channel == null) {
                    return;
                }
                group.remove(channel);
            }

            if (MessageTypeEnum.DISSOLUTION_GROUP == messageTypeEnum) {
                GROUP_CONTEXT_MAP.remove(messageSendDto.getContactId());
                group.close();
            }
        }

    }
    public void addGroup(String userId, String groupId) {
        Channel channel = USER_CONTEXT_MAP.get(userId);
        add(groupId, channel);
    }

    private void add(String groupId, Channel context) {
        ChannelGroup group = GROUP_CONTEXT_MAP.get(groupId);
        if (group == null) {
            group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
            GROUP_CONTEXT_MAP.put(groupId, group);
        }
        if (context == null) {
            return;
        }
        group.add(context);
    }


}
